---
title: Path concepts
description: Explanation of the "path" property of rules and groups
hide_table_of_contents: true
---

import { SandpackRQB } from '@site/src/components/SandpackRQB';

While the `id` property uniquely identifies rules and groups, it doesn't indicate their position within the query hierarchy. React Query Builder uses a "path" concept to locate and update query objects based on their structural position.

The `path` property is an integer array that uniquely identifies each rule and group's location within a query. The root query group has a `path` of `[]`, while all nested rules and groups have paths reflecting their position within their ancestor groups' `rules` arrays.

Each object's `path` equals its parent group's `path` plus its index within the parent's `rules` array: `path = [...parentPath, index]`.

This example query shows the `path` for each rule and group with explanatory comments:

```ts
// [] (the root group)
const query: RuleGroupType = {
  combinator: 'and',
  rules: [
    // [0] (the first, aka zeroth, element in the root rules array)
    { field: 'f1', operator: '=', value: 'v1' },
    // [1] (the second element in the root rules array is a sub-group)
    {
      combinator: 'or',
      rules: [
        // [1, 0] (the first element within the rules array
        //         of the group occupying the second position
        //         in the root rules array)
        { field: 'f2', operator: '=', value: 'v2' },
        // [1, 1] (the second element within the rules array
        //         of the group occupying the second position
        //         in the root rules array)
        { field: 'f3', operator: '=', value: 'v3' },
      ],
    },
  ],
};
```

The first rule has `path` `[0]` (index 0 in the root `rules` array). The sub-group has `path` `[1]` (index 1 in the root array). Child rules within that group have paths starting with `1` (their parent's path) followed by their own indices.

## Finding a `path`

The [`findPath`](../utils/misc#findpath) function locates specific rules or groups for examination or updates. Using the query above:

```ts
findPath([1, 0], query);
```

Returns:

```json
{ "field": "f2", "operator": "=", "value": "v2" }
```

## Example

While most scenarios don't require direct `path` interaction, it's useful when custom components need to access other query parts.

For example, if a custom value editor needs sibling rule values, you can retrieve the full query object using the [`useQueryBuilderQuery`](../utils/hooks#usequerybuilderquery) hook (which connects to React Query Builder's Redux store), then find sibling rules using `getParentPath` and `findPath`.

:::info

Before version 7, custom components only received props for their specific rule or group. Additional data (like the root query) required the [`context` prop](../components/querybuilder#context).

The `context` prop remains available, but query retrieval no longer requires it.

:::

<SandpackRQB rqbVersion={7} options={{ editorHeight: 444, activeFile: "/CustomValueEditor.tsx" }}>

```tsx CustomValueEditor.tsx
import {
  RuleGroupType,
  RuleType,
  ValueEditor,
  ValueEditorProps,
  findPath,
  getParentPath,
  useQueryBuilderQuery,
} from 'react-querybuilder';

export const CustomValueEditor = (props: ValueEditorProps) => {
  // Get the full query object
  const query = useQueryBuilderQuery();
  // Get the path of this rule's parent group
  const parentPath = getParentPath(props.path);
  // Find the parent group object in the query
  const parentGroup = findPath(parentPath, query) as RuleGroupType;
  const id = findPath(props.path, query)!.id;
  // Get a comma-separated list of all sibling rule values
  const siblingValues = (
    parentGroup.rules.filter(
      r =>
        // filter out groups
        !('rules' in r) &&
        // filter out self
        r.id !== id
    ) as RuleType[]
  )
    // map the `value` property
    .map(r => r.value)
    // join with comma
    .join(', ');

  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <ValueEditor {...props} />
      <span>Others: {siblingValues}</span>
    </div>
  );
};
```

```tsx
import { useState } from 'react';
import { QueryBuilder } from 'react-querybuilder';
import { CustomValueEditor } from './CustomValueEditor';
import { defaultQuery, fields, operators } from './constants';

export default function App() {
  const [query, setQuery] = useState(defaultQuery);

  return (
    <QueryBuilder
      fields={fields}
      operators={operators}
      query={query}
      onQueryChange={setQuery}
      controlElements={{ valueEditor: CustomValueEditor }}
    />
  );
}
```

```ts constants.ts
import { defaultOperators, Field, RuleGroupType } from 'react-querybuilder';

export const operators = defaultOperators.filter(op => op.name === '=');

export const fields: Field[] = [
  { name: 'field1', label: 'Field 1' },
  { name: 'field2', label: 'Field 2' },
  { name: 'field3', label: 'Field 3' },
  { name: 'field4', label: 'Field 4' },
];

export const defaultQuery: RuleGroupType = {
  combinator: 'and',
  rules: [
    { field: 'field1', operator: '=', value: '1' },
    { field: 'field2', operator: '=', value: '2' },
    { field: 'field3', operator: '=', value: '3' },
    { field: 'field4', operator: '=', value: '4' },
  ],
};
```

```css
.queryBuilder .rule {
  align-items: flex-start;
}

span {
  color: gray;
}
```

</SandpackRQB>
